﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HenIT.Data.SqlClient;
using System.Data.SqlClient;
using System.Data;

namespace EventScavenger
{
	public partial class EventScavengerDAL : GenericSQLServerDAL
	{
		private SqlConnection insertConn;
		private System.Threading.Mutex insertMutex = new System.Threading.Mutex();
		private System.Threading.Mutex connResetMutex = new System.Threading.Mutex();

		#region Test Connection
		internal bool TestConnection()
		{
			bool success = false;
			string sql = "select getdate()";
			try
			{
				ExecuteSQL(sql);
				success = true;
			}
			catch (Exception ex)
			{
				lastError = ex.ToString();
			}
			return success;
		}
		internal int TestConnectionGetEntryCount()
		{
            string sql = "GetEventlogRowCount";
            return (int)GetSingleValue(sql);
		}
        internal double GetDatabaseVersion()
        {
            double version = 0;
            string sql = "GetSettingValue";
            SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@SettingName", "DatabaseVersion")
				};
            string rawVersion = "";
            try
            {
                rawVersion = GetSingleValue(sql, CommandType.StoredProcedure, parms).ToString();
                version = double.Parse(rawVersion);
            }
            catch(Exception ex)
            {
                if (ex is System.FormatException && ex.Message.Contains("Input string was not in a correct format"))
                {
                    if (rawVersion.Contains('.'))
                    {
                        version = double.Parse(rawVersion.Split('.')[0]);
                    }
                    else
                        throw;
                }
                else
                    throw;
            }
            return version;
        }

		#endregion

		#region Collectors
		internal Collector GetCollectorByName(string collectorName)
		{
			string sql = "GetCollectorByName";
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@CollectorName", collectorName)
				};

			Collector collector = null;
			try
			{
				DataSet collectords = base.GetDataSet(sql, CommandType.StoredProcedure, parms);
				if (collectords.Tables.Count > 0)
				{
					collector = (from DataRow row in collectords.Tables[0].Rows
								 select new Collector()
								 {
									 Id = (int)row["CollectorID"],
									 Name = row["Name"].ToString(),
									 ImportsEnabled = (bool)row["ImportsEnabled"],
									 ImportFrequency = (int)row["ImportFrequencyMinutes"],
									 MainThreadUpdateFrequencySec = (int)row["MainThreadUpdateFrequencySec"],
									 UseBatchInserts = (bool)row["UseBatchInserts"],
									 InsertBatchSize = (int)row["InsertBatchSize"],
									 SqlCommandTimeOutSec = (int)row["SqlCommandTimeOutSec"],
									 LogDuplicateWarnings = (bool)row["LogDuplicateWarnings"]
								 }
								 ).First();
				}
			}
			catch (Exception ex)
			{
				lastError = ex.ToString();
			}
			return collector;
		}

		#endregion

		#region Maintenance
		internal string GetMaintenanceRunner()
		{
			string maintenanceRunner = "";
			string sql = "GetSettingValue";
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@SettingName", "MaintenanceRunner")
				};
			object tmpVal = base.GetSingleValue(sql, CommandType.StoredProcedure, parms);
			if (tmpVal != DBNull.Value)
				maintenanceRunner = tmpVal.ToString();
			return maintenanceRunner;
		}
		internal bool IsMaintenanceEnabled()
		{
			bool isEnabled = false;
			string sql = "GetSettingValue";
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@SettingName", "MaintenanceEnabled")
				};
			object tmpVal = base.GetSingleValue(sql, CommandType.StoredProcedure, parms);
			if (tmpVal != DBNull.Value)
				isEnabled = bool.Parse(tmpVal.ToString());
			return isEnabled;
		}
		internal DateTime GetMaintenanceLastRunTime()
		{
			DateTime lastRun = new DateTime(2000, 1, 1);
			string sql = "GetSettingValue";
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@SettingName", "MaintenanceLastRun")
				};
			object tmpVal = base.GetSingleValue(sql, CommandType.StoredProcedure, parms);
			if (tmpVal != DBNull.Value)
				lastRun = DateTime.Parse(tmpVal.ToString());
			return lastRun;
		}
		internal int GetMaintenanceFrequencyMinutes()
		{
			int maintenanceFrequencyMinutes = 5;
			string sql = "GetSettingValue";
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@SettingName", "MaintenanceFrequencyMinutes")
				};
			object tmpVal = base.GetSingleValue(sql, CommandType.StoredProcedure, parms);
			if (tmpVal != DBNull.Value)
				maintenanceFrequencyMinutes = int.Parse(tmpVal.ToString());
			return maintenanceFrequencyMinutes;
		}
		internal void SetMaintenanceLastRunTime()
		{
			string sql = "SetMaintenanceLastRunTime";
			base.ExecuteSP(sql);
		}
		internal int GetMaintenanceTimeOutSeconds()
		{
			int maintenanceTimeOutSeconds = 300;
			string sql = "GetSettingValue";
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@SettingName", "MaintenanceTimeOutSeconds")
				};
			object tmpVal = base.GetSingleValue(sql, CommandType.StoredProcedure, parms);
			if (tmpVal != DBNull.Value)
				maintenanceTimeOutSeconds = int.Parse(tmpVal.ToString());
			return maintenanceTimeOutSeconds;
		}
		internal void RunMaintenance(int commandTimeOut)
		{
			string sql = "DoMaintenance";
			base.ExecuteSP(sql, null, commandTimeOut);
		}
		#endregion

		#region Create history
		public bool IsRunCreateHistoryEnabled()
		{
			string sql = "GetSettingValue";
			bool maintenanceEnabled = false;
			SqlParameter[] parameters = new SqlParameter[] 
				{
					new SqlParameter("@SettingName", "RunCreateHistoryEnabled")
				};
			object tmpval = GetSingleValue(sql, CommandType.StoredProcedure, parameters);
			if (tmpval != DBNull.Value)
				maintenanceEnabled = bool.Parse(tmpval.ToString());
			return maintenanceEnabled;
		}
		public void SetNextCreateHistoryTime()
		{
			string sql = "SetNextCreateHistoryTime";
			base.ExecuteSP(sql);
		}
		public DateTime GetNextCreateHistoryTime()
		{
			DateTime nextCreateHistoryTime = new DateTime(2000, 1, 1);
			string sql = "GetSettingValue";
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@SettingName", "NextCreateHistoryTime")
				};
			object tmpVal = base.GetSingleValue(sql, CommandType.StoredProcedure, parms);
			if (tmpVal != DBNull.Value)
				nextCreateHistoryTime = DateTime.Parse(tmpVal.ToString());

			return nextCreateHistoryTime;
		}
		public void RunCreateHistory()
		{
			string sql = "DoCreateHistory";
			SqlParameter[] parms = new SqlParameter[] { };
			base.ExecuteSP(sql, parms, 3600); // 1 hour
		}
		#endregion

		#region MachineLog methods
		public List<MachineLogEntry> GetMachineLogListByCollector(string collectorName)
		{
			List<MachineLogEntry> list = new List<MachineLogEntry>();
			string sql = "SelectMachineLogListByCollector";
			lastError = "";
			try
			{
				DataSet machineList = base.GetDataSet(sql, CommandType.StoredProcedure,
					new SqlParameter[] { new SqlParameter("@Collector", collectorName) });
				if (machineList.Tables.Count > 0)
				{
					list.AddRange(from DataRow row in machineList.Tables[0].Rows
								  select new MachineLogEntry(
								  row["Machine"].ToString(),
								  row["LogName"].ToString(),
								  (int)row["PollFrequency"])
								  {
									  Collector = row["Collector"].ToString(),
									  CollectorId = (int)row["CollectorID"],
									  Enabled = (bool)row["Enabled"],
									  LastPollTime = row["LastPollTime"] == null ? new DateTime(2000,1,1) : (DateTime)row["LastPollTime"],
									  PollFilterID = I2Null(row["PollFilterID"]),
                                      DBImportEnabled = (bool)row["DBImportEnabled"],
                                      DBImportServer = N(row["DBImportServer"]),
                                      DBImportDatabase = N(row["DBImportDatabase"])
								  }
								 );
					foreach (MachineLogEntry mle in list)
					{
						if (mle.PollFilterID > 0)
						{
							mle.PollFilter = GetPollFilterByID(mle.PollFilterID);
						}
						mle.NewestEntry = GetMachineLogNewestEntry(mle.MachineLogID);
					}
				}
			}
			catch (Exception ex)
			{
				lastError = ex.ToString();
			}
			return list;
		}
		public void SetLastMachineLogPollingTime(string machine, string logName, DateTime lastPollTime)
		{
			string sql = "SetLastPollTimeForMachineLog";
			try
			{
				//sqlAccessBusy.WaitOne();
				SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@Machine", machine),
					new SqlParameter("@LogName", logName),
					new SqlParameter("@LastPollTime", lastPollTime.AddSeconds(-3)) //Allow grace period of 3 seconds to avoid events being missed
				};
				base.ExecuteSP(sql, parms);
			}
			catch { throw; }
			finally
			{
				//sqlAccessBusy.ReleaseMutex();
			}
		}
		public MachineLogEntry GetMachineLogEntry(string machine, string logName)
		{
			MachineLogEntry machineLogEntry = new MachineLogEntry(machine, logName);
			string sql = "SelectMachineLogEntry";
			try
			{
				SqlParameter[] parameters = new SqlParameter[] 
				{
					new SqlParameter("@Machine", machineLogEntry.Machine),
					new SqlParameter("@LogName", machineLogEntry.LogName),
				};
				DataSet mleds = GetDataSet(sql, CommandType.StoredProcedure, parameters);
				if (mleds.Tables.Count > 0 && mleds.Tables[0].Rows.Count > 0)
				{
					DataRow r = mleds.Tables[0].Rows[0];
					machineLogEntry = new MachineLogEntry(machine, logName);
					machineLogEntry.MachineLogID = (int)r["MachineLogID"];
					machineLogEntry.CollectorId = (int)r["CollectorID"];
					machineLogEntry.Collector = r["Collector"].ToString();
					machineLogEntry.Enabled = (bool)r["Enabled"];
					machineLogEntry.PollFrequency = (int)r["PollFrequency"];
					machineLogEntry.MaxEntryCount = (int)r["MaxEntryCount"];
					machineLogEntry.LastPollTime = (r["LastPollTime"] == DBNull.Value ? new DateTime(2000, 1, 1) : (DateTime)r["LastPollTime"]);
					if (r["PollFilterID"] != DBNull.Value)
					{
						machineLogEntry.PollFilterID = (int)r["PollFilterID"];
						machineLogEntry.PollingFilterName = r["PollingFilterName"].ToString();
						if (r["PollFilterLastChanged"] != DBNull.Value)
						{
							machineLogEntry.PollFilterLastChanged = (DateTime)r["PollFilterLastChanged"];
						}
					}
					try
					{
						machineLogEntry.DBImportEnabled = (bool)r["DBImportEnabled"];
                        machineLogEntry.DBImportServer = N(r["DBImportServer"]);
                        machineLogEntry.DBImportDatabase = N(r["DBImportDatabase"]);
					}
					catch { }
				}
				else
				{
					machineLogEntry.MachineLogID = -1;
					machineLogEntry.Enabled = false;
				}
			}
			catch (Exception ex)
			{
				lastError = ex.ToString();
			}
			return machineLogEntry;
		}
		private DateTime GetMachineLogNewestEntry(int machineLogID)
		{
			DateTime lastEntryDate = new DateTime(2000, 1, 1);
			string sql = "GetMachineLogMaxTimeGenerated";
			SqlParameter[] parameters = new SqlParameter[] 
			{
				new SqlParameter("@MachineLogID",machineLogID)
			};
			object t = base.GetSingleValue(sql, CommandType.StoredProcedure, parameters);
			if (t != DBNull.Value)
			{
				lastEntryDate = ((DateTime)t).AddSeconds(-1); //make sure we get all possible entries
			}
			return lastEntryDate;
		}
		private DateTime GetMachineLogNewestEntry(MachineLogEntry mle)
		{
			return GetMachineLogNewestEntry(mle.MachineLogID);
		}
		#endregion

		#region Polling filter methods
		public PollFilter GetPollFilterByID(int pollFilterId)
		{
			PollFilter pollFilter = null;
			string sql = "SelectPollFilter";
			SqlParameter[] parameters = new SqlParameter[] 
				{
					new SqlParameter("@PollFilterID", pollFilterId),
				};
			try
			{
				DataSet pfds = GetDataSet(sql, CommandType.StoredProcedure, parameters);
				if (pfds.Tables.Count > 0 && pfds.Tables[0].Rows.Count > 0)
				{
					pollFilter = new PollFilter();
					DataRow r = pfds.Tables[0].Rows[0];
					pollFilter.PollFilterID = pollFilterId;
					pollFilter.Name = r["Name"].ToString();
					pollFilter.MessageContains = (r["MessageContains"] == DBNull.Value ? "" : r["MessageContains"].ToString());
					pollFilter.ExcludeInfo = (bool)r["ExcludeInfo"];
					pollFilter.ExcludeWarn = (bool)r["ExcludeWarn"];
					pollFilter.ExcludeErr = (bool)r["ExcludeErr"];
					pollFilter.ExcludeSucAud = (bool)r["ExcludeSucAud"];
					pollFilter.ExcludeFailAud = (bool)r["ExcludeFailAud"];
					pollFilter.LastChanged = (r["LastChanged"] == DBNull.Value ? null : (DateTime?)r["LastChanged"]);
				}
				if (pollFilter != null)
				{
					sql = "SelectPollFilterEventIDsByPollFilterID";
					SqlParameter[] parameters2 = new SqlParameter[] 
					{
						new SqlParameter("@PollFilterID", pollFilterId),
					};
					DataSet pfeidds = GetDataSet(sql, CommandType.StoredProcedure, parameters2);
					if (pfeidds.Tables.Count > 0 && pfeidds.Tables[0].Rows.Count > 0)
					{
						foreach (DataRow r in pfeidds.Tables[0].Rows)
						{
							if ((bool)r["Exclude"])
							{
								pollFilter.ExcludeEventIDs.Add((int)r["EventID"]);
							}
							else
							{
								pollFilter.IncludeEventIDs.Add((int)r["EventID"]);
							}
						}
					}
					sql = "SelectPollFilterSourcesByPollFilterID";
					SqlParameter[] parameters3 = new SqlParameter[] 
					{
						new SqlParameter("@PollFilterID", pollFilterId),
					};
					DataSet pfsds = GetDataSet(sql, CommandType.StoredProcedure, parameters3);
					if (pfsds.Tables.Count > 0 && pfsds.Tables[0].Rows.Count > 0)
					{
						foreach (DataRow r in pfsds.Tables[0].Rows)
						{
							if ((bool)r["Exclude"])
							{
								pollFilter.ExcludeSources.Add(r["Source"].ToString());
							}
							else
							{
								pollFilter.IncludeSources.Add(r["Source"].ToString());
							}
						}
					}
				}
				if (pollFilter.ExcludeEventIDs.Count > 0 ||
					pollFilter.IncludeEventIDs.Count > 0 ||
					pollFilter.ExcludeSources.Count > 0 ||
					pollFilter.IncludeSources.Count > 0 ||
					pollFilter.MessageContains.Length > 0)
				{
					pollFilter.UseListFilters = true;
				}
				else
					pollFilter.UseListFilters = false;
			}
			catch (Exception ex)
			{
				lastError = ex.ToString();
			}
			return pollFilter;
		}
		#endregion

		#region InsertEventLogEntry
		public void InsertEventLogEntry(
				string computerName,
				string eventLogName,
				int recordNumber,
				int eventId,
				DateTime timeGenerated,
				string sourceName,
				string eventTypeName,
				string strings,
				string message,
				string category,
				string userName
			)
		{
			try
			{
				connResetMutex.WaitOne();
				if (insertConn == null || insertConn.State != ConnectionState.Open)
				{
#if DEBUG
					System.Diagnostics.Trace.WriteLine(
						string.Format("Resetting connection - {0}\\{1}\\{2}\\{3}\\{4}",
						computerName, eventLogName, sourceName, eventId, eventTypeName));
#endif
					insertConn = null;
					insertConn = new SqlConnection(connectionString);
                    OpenConnectionWithRetries(insertConn);
				}
			}
			catch { throw; }
			finally
			{
				connResetMutex.ReleaseMutex();
			}
			try
			{
				string sql = "InsertEventLogEntry";
				SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@ComputerName", computerName),
					new SqlParameter("@EventLog", eventLogName),
					new SqlParameter("@RecordNumber", recordNumber),
					new SqlParameter("@EventID", eventId),
					new SqlParameter("@TimeGenerated", timeGenerated),
					new SqlParameter("@SourceName", sourceName),
					new SqlParameter("@EventTypeName", eventTypeName.Substring(0,1).ToUpper()),
					new SqlParameter("@Strings", strings),
					new SqlParameter("@Message", message),
					new SqlParameter("@Category", category),
					new SqlParameter("@UserName", userName)
				};
				using (SqlCommand cmnd = new SqlCommand(sql, insertConn))
				{
					cmnd.CommandType = CommandType.StoredProcedure;
					cmnd.CommandTimeout = CommandTimeout;
					cmnd.Parameters.AddRange(parms);
					try
					{
						insertMutex.WaitOne(); //make sure only one insert is done at a time
						cmnd.ExecuteNonQuery();
					}
					catch { throw; }
					finally
					{
						insertMutex.ReleaseMutex();
					}
				}
				DoRaiseDBAccessInsertsEvent(1);
			}
			catch (System.Data.SqlClient.SqlException innerseex)
			{
				//Ignoring duplicates - they are in the database already...
				if (innerseex.Message.Contains("Violation of PRIMARY KEY constraint") ||
					innerseex.Message.Contains("Cannot insert duplicate key"))
					DoRaiseDBAccessInsertDuplicates();
				else
				{
					throw;
				}
			}
			catch //rethrow the rest
			{
				throw;
			}
		}
		public string InsertEventLogEntries(System.IO.Stream xml)
		{
			string infoResult = "";
			#region Connection reset
			try
			{
				connResetMutex.WaitOne();
				if (insertConn == null || insertConn.State != ConnectionState.Open)
				{
					insertConn = null;
					insertConn = new SqlConnection(connectionString);
                    OpenConnectionWithRetries(insertConn);
				}
			}
			catch { throw; }
			finally
			{
				connResetMutex.ReleaseMutex();
			}
			#endregion

            string debugtext = "";

#if DEBUG
            try
            {
                System.IO.StreamReader reader = new System.IO.StreamReader(xml);
                if (xml.Length < 32765)
                    debugtext = reader.ReadToEnd();
                else
                {
                    char[] b = new char[32000];
                    reader.Read(b, 0, 32000);
                    for (int i = 0; i < 32000; i++)
                    {
                        debugtext += b[i];
                    }
                }
            }
            catch (Exception ex)
            {
                DoRaiseErrorMessage(string.Format("Exception in debugging in InsertEventLogEntries\r\n{0}\r\n{1}", ex.Message, debugtext));
            }
            xml.Position = 0;
#endif
         

			string sql = "InsertEventLogEntries";
			System.Data.SqlTypes.SqlXml sxl = new System.Data.SqlTypes.SqlXml(xml);
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@xml", SqlDbType.Xml) { Value = sxl}
				};
			using (SqlCommand cmnd = new SqlCommand(sql, insertConn))
			{
				cmnd.CommandType = CommandType.StoredProcedure;
				cmnd.CommandTimeout = CommandTimeout;
				cmnd.Parameters.AddRange(parms);
				try
				{
					insertMutex.WaitOne(); //make sure only one insert is done at a time
					using (SqlDataReader r = cmnd.ExecuteReader())
					{
						if (r.Read())
						{
							int duplicates = (int)r["Duplicates"];
							int repeats = (int)r["Repeats"];
							int inserts = (int)r["Inserts"];
							if (duplicates > 1 || repeats > 0)
							{
								infoResult = string.Format("{0} inserts, {1} duplicates, {2} repeats, {3} failures, " +
							"{4}ms duration, last err: {5}",
								r["Inserts"],
								r["Duplicates"],
								r["Repeats"],
								r["InsertFailures"],
								r["MSDuration"],
								r["LastErrorMsg"]);
							}
							DoRaiseDBAccessInsertsEvent(inserts);
						}
					}
					
				}
				catch (Exception ex)
                {
#if DEBUG
                    DoRaiseErrorMessage(string.Format("Exception in InsertEventLogEntries\r\n{0}\r\n{1}", ex.Message, debugtext));
#endif
                    
                    throw; 
                }
				finally
				{
					insertMutex.ReleaseMutex();
				}
			}
			return infoResult;
		}
		#endregion

		#region Import logs
		public List<ImportForeignLog> SelectImportLogsByCollector(int collectorId)
		{
			string sql = "SelectImportLogsByCollector";
			List<ImportForeignLog> list = new List<ImportForeignLog>();
			SqlParameter[] parms = new SqlParameter[] {
					new SqlParameter("@CollectorID", collectorId)
				};
			try
			{
				DataSet importList = base.GetDataSet(sql, CommandType.StoredProcedure, parms);
				if (importList.Tables.Count > 0)
				{
					list.AddRange(from DataRow row in importList.Tables[0].Rows
								  select new ImportForeignLog()
								  {
									  SQLServer = row["Server"].ToString(),
									  Database = row["Database"].ToString(),
									  Machine = row["Machine"].ToString(),
									  LogName = row["LogName"].ToString(),
                                      MachineLogId = (int)row["MachineLogID"]
								  }
								 );
				}
			}
			catch (Exception ex)
			{
				lastError = ex.ToString();
			}

			return list;
		}
        internal List<EventLogEntryEx> GetImportLogEntries(string dbServer, string database, MachineLogEntry logToImport, int batchSize, int lastRecordNumber)
		{
			List<EventLogEntryEx> entryList = new List<EventLogEntryEx>();
			string sourceConnectionString = "Server=" + dbServer + ";Database=" + database + ";Trusted_Connection=True;";
			DateTime fromDate; DateTime toDate = DateTime.Now;
			string lastStep = "Importing from " + dbServer + "\\" + database;
			try
			{
				fromDate = logToImport.LastPollTime;
				using (SqlConnection connSource = new SqlConnection(sourceConnectionString))
				{
					lastStep = "Open source connection";
                    OpenConnectionWithRetries(connSource);
					lastStep = "Check machine-log exists on destination";
					MachineLogEntry updatedLog = GetMachineLogEntry(logToImport.Machine, logToImport.LogName);
					if (updatedLog.MachineLogID > 0)
					{
						//lastStep = "Get machine-log newest entry date";
						//fromDate =  GetMachineLogNewestEntry(updatedLog);
						lastStep = "Get entries from distant source";
                        entryList = GetRemoteEntries(connSource, logToImport, fromDate, toDate, batchSize, lastRecordNumber);
					}
				}
			}
			catch (Exception ex)
			{
				throw new Exception("Last Step: " + lastStep, ex);
			}
			return entryList;
		}
		public bool ImportLog(string dbServer, string database, List<MachineLogEntry> logs, int batchSize)
		{
			bool done = true;
			string sourceConnectionString = "Server=" + dbServer + ";Database=" + database + ";Trusted_Connection=True;";
			DateTime fromDate; DateTime toDate = DateTime.Now;
			int recordsCopied;
			int duplicates;
			string lastStep = "ImportLog start";
			try
			{
				using (SqlConnection connSource = new SqlConnection(sourceConnectionString))
				{
					lastStep = "Open source connection";
                    OpenConnectionWithRetries(connSource);


					foreach (MachineLogEntry log in logs)
					{
						lastStep = "Check machine-log exists on destination";
						MachineLogEntry updatedLog = GetMachineLogEntry(log.Machine, log.LogName);
						if (updatedLog.MachineLogID > 0)
						{
							lastStep = "Get machine-log newest entry date";
							fromDate = GetMachineLogNewestEntry(updatedLog);
							lastStep = "Get entries from distant source";
							List<EventLogEntryEx> entryList = GetRemoteEntries(connSource, log, fromDate, toDate, batchSize);
							if (done) //only mark as not done if not done already and list is bigger than batchsize
								done = entryList.Count < batchSize;
							recordsCopied = 0;
							duplicates = 0;
							lastStep = "For each source insert into destination database";
							foreach (EventLogEntryEx eventEntry in entryList)
							{
								try
								{
									lastStep = "Add entry";
									InsertEventLogEntry(log.Machine, log.LogName,
										eventEntry.Index, eventEntry.InstanceId, eventEntry.TimeGenerated,
										eventEntry.Source, eventEntry.EntryType, "", eventEntry.Message, 
										eventEntry.Category, eventEntry.UserName);
									recordsCopied++;
								}
								catch (Exception ex)
								{
									lastStep = "Logging error - " + ex.Message;
									if (
										ex.Message.Contains("Violation of PRIMARY KEY constraint") ||
										ex.Message.Contains("Cannot insert duplicate key")
										)
									{
										duplicates++;
									}
									else
									{
										DoRaiseErrorMessage("Error adding: " + eventEntry.ToString() + "   \r\n" + ex.ToString());
									}
								}
							}

							DoRaiseSyncInfoMessage("Import done: " + dbServer + "\\" + database + "\\" + log.Machine.ToString() + "\\" + log.LogName.ToString() + "\r\n" +
										"Records copied: " + recordsCopied.ToString() + "\r\n" +
										"Duplicates ignored: " + duplicates.ToString());
						}
						else
						{
							DoRaiseErrorMessage("Import failed! The destination log entry does not exist!\r\nSource:" + dbServer + "\\" + database + "\\" + log.Machine.ToString());
						}

					}
				}
				lastStep = "Import done";
			}
			catch (Exception ex)
			{
				throw new Exception("Last Step: " + lastStep, ex);
			}
			return done;
		}
        private List<EventLogEntryEx> GetRemoteEntries(SqlConnection connSource, MachineLogEntry mle, DateTime fromDate, DateTime toDate, int batchSize = 1000, int lastRecordNumber = 0)
		{
			List<EventLogEntryEx> list = new List<EventLogEntryEx>();

			string sql = "SelectEventLogEntriesByMachineLogName";
			SqlParameter[] parameters = new SqlParameter[] 
			{
				new SqlParameter("@FromDate", fromDate),
				new SqlParameter("@ToDate", toDate),
				new SqlParameter("@ComputerName", mle.Machine),
				new SqlParameter("@EventLog", mle.LogName),
				new SqlParameter("@BatchSize", batchSize),
				new SqlParameter("@RecordNumber", lastRecordNumber)
			};

			DataSet dsEntries = new DataSet();
			DoRaiseDBAccessEvent();
			try
			{
				using (SqlCommand cmnd = new SqlCommand(sql, connSource))
				{
					cmnd.CommandTimeout = CommandTimeout;
					cmnd.CommandType = CommandType.StoredProcedure;
					cmnd.Parameters.AddRange(parameters);
					using (SqlDataAdapter da = new SqlDataAdapter(cmnd))
					{
						da.Fill(dsEntries);
					}
				}
			}
			catch
			{
				DoRaiseDBAccessErrorsEvent();
				throw;
			}

			if (dsEntries.Tables.Count > 0)
			{
				list.AddRange(
						from DataRow row in dsEntries.Tables[0].Rows
						select new EventLogEntryEx()
						{
							Index = int.Parse(row["RecordNumber"].ToString()),
							InstanceId = int.Parse(row["EventID"].ToString()),
							TimeGenerated = DateTime.Parse(row["TimeGenerated"].ToString()),
							Source = row["SourceName"].ToString(),
							EntryType = row["EventTypeName"].ToString(),
							Message = row["Message"].ToString(),
							Category = row["Category"] == DBNull.Value ? "" : row["Category"].ToString(),
							UserName = row["UserName"] == DBNull.Value ? "" : row["UserName"].ToString()
						}
					   );
			}
			return list;
		} 
		#endregion

        #region Null handling
        private int I2Null(object value, int defaultValue = 0)
		{
			if (value == null || value == System.DBNull.Value)
				return defaultValue;
			else if (value is int)
				return (int)value;
			else
				return defaultValue;
		}        
        private string N(object anyVal)
        {
            if (anyVal == null)
                return "";
            else
                return anyVal.ToString();
        }
        #endregion
	}
}
